﻿// owner 蒋家伟

#pragma once
#include <cstdint>

// 方法描述 : 依赖于QuickCastDefine中关于类别定义的快速cast, 支持多继承【可以正确计算地址偏移】
// 优势     : 
// 1、如果没有定义虚函数时 dynamic_cast 无法使用; 
// 2、类型强转非继承体系后，dynamic_cast将返回为空，而quick_cast任可以保证cast成功 
// 例: class A:public B, class C; A a, dynamic_cast<B*>((C*)&a) 为nullptr， 而 quick_cast<B>((C*)&a) 成功，只要能通过编译就能保证cast的有效性，要么断开定义体系为nullptr要么正确。保证可靠性
// 使用方法 : 与dynamic_cast无异 
// 性能比较 :
// 1 亿级别的cast存在3倍左右的性能差距（Release -o2）
// note ：Debug模式下dynamic性能优于quick_cast 
// Debug :          quick_cast      time : 7501 ms
//                  dynamic_cast    time : 5257 ms
// Release :        quick_cast      time : 880 ms
//                  dynamic_cast    time : 3412 ms
// 目前quick_cast的性能瓶颈在cast_imp中, 
// 设计思路 : 
// 1、首先能保证对象的正确cast，其次是保证断开定义的继承体系返回空指针或者静态检测错误。
// 2、需要确定的输入输出，一定是From ->To两个标识正确。不能由于父类定义而当前没定义，通过静态函数调用到父类的方法中去了。这样会使得从基类往子类转换时出现错误。
// 目前使用typeid解决了问题2，todo 更好的思路解决问题2

namespace jsdk
{
    template<bool, typename T1, typename T2>
    struct IF
    {
        using type = T1;
    };

    template<typename T1, typename T2>
    struct IF<false, T1, T2>
    {
        using type = T2;
    };
}

#define quick_cast safe_cast

template< typename To, typename From, typename RT = jsdk::IF<std::is_const<From>::value, std::add_const_t<To>, To>::type>
RT* safe_cast(From* pFrom)
{
    if (pFrom == nullptr)
        return nullptr;
    static const char* s_pT = typeid(To).name();
    uint64_t address_cast = 0;
    if (pFrom->cast_imp(s_pT, address_cast))
    {
        return reinterpret_cast<RT*>(address_cast);
    }
    return nullptr;
}

// 类别描述 ：判断模版T是否支持quick_cast
template<typename T>
struct is_define_quick_cast
{
    template<typename U, bool(U::*)(const char*, uint64_t&) const = &U::cast_imp >
    static constexpr int check(U*);
    static constexpr char check(...);
    static constexpr bool value = sizeof(check(static_cast<T*>(nullptr))) == sizeof(int);
};

